//////////////////////////////////////////////
//Vector3f.h                                //
//This is my implementation of a 3d vector	//
//class. It is still in construction due to //
//my concerns over my general vector maths	//
//skills.  Also so much of GLTools is based //
//around the math3D library I started having//
//to convert from its vector class into my	//
//own one which seemed an exercise in		//
//futility.  However I plan to work on it in//
//my spare time along with some other		//
//personal versions of classes implemented	//
//in GLTools such as my own frame class to	//
//replace GLFrame which never seemed to have//
//the functionality to do quite what I		//
//wanted it to.  Eventually I want to have a//
//complete set of classes so I don't need to//
//use GLTools at all.						//
//////////////////////////////////////////////
#pragma once

#ifndef VECTOR3F
#define VECTOR3F

#include<cmath>
#include<math3d.h>

class Vector3f
{
public:
	Vector3f(float ix = 0.0f, float iy = 0.0f, float iz = 0.0f): x(ix), y(iy), z(iz){}
	Vector3f(Vector3f directionv, float magnitude)
	{
		if(directionv.x != 0)
		{
			x = magnitude * directionv.x;
		}
		else
		{
			x = 0;
		}
		if(directionv.y != 0)
		{
			y = magnitude * directionv.y;
		}
		else
		{
			y = 0;
		}
		if(directionv.z != 0)
		{
			z = magnitude * directionv.z;
		}
		else
		{
			z = 0;
		}
	}
	~Vector3f(){}

	// Operations of a vector on a vector
	inline const Vector3f operator+(const Vector3f& v) const{return Vector3f(x + v.x, y + v.y, z + v.z);}
	inline const Vector3f operator-(const Vector3f& v) const{return Vector3f(x - v.x, y - v.y, z - v.z);}
	inline const Vector3f operator*(const float& f) const{return Vector3f(x * f , y * f , z * f);}
	inline const Vector3f operator/(const float& f) const{return Vector3f(x / f , y / f , z / f);}
	
	inline const Vector3f& operator+=(const Vector3f& v){x += v.x;	y += v.y; z += v.z; return *this;}
	inline const Vector3f& operator-=(const Vector3f& v){x -= v.x;	y -= v.y; z -= v.z; return *this;}
	inline const Vector3f& operator*=(const float& f){x *= f;	y *= f; z *= f; return *this;};
	//inline const Vector3f& operator/=(const Vector3f& v){x /= v.x;	y /= v.y;return *this;};

	inline float dotProduct(Vector3f v){return((x * v.x) + (y * v.y) + (z * v.z));}


	inline Vector3f crossProduct(const Vector3f& v){return Vector3f((y * v.z)-(z * v.y),(z * v.x)-(x * v.z),(x * v.y)-(y * v.x));}

	//length 
	inline float length(){
		
		float tempx = x * x;
		float tempy = y*y ;
		float tempz = z*z;

		float tempt = tempx + tempy + tempz;
		
		
		return sqrt((x * x) + (y * y) + (z * z));}

	//get unit length of vector
	void normalizeMe(){
		float len = length();
		x /= len;
		y /= len;
		z /= len;
	}

	void fromM3D(M3DVector3f m){
		x=m[0];
		y=m[1];
		z=m[2];
	}
	void toM3D(float *m){
		m[0] = x;
		m[1] = y;
		m[2] = z;
	}

	void clear()
	{
		x = 0;
		y = 0;
		z = 0;
	}

	bool isZero(){
		bool b = false;
		if(x == 0 && y==0 && z==0){	
			b=true;
		}
		return b;
	}

	float combine(){
		float tmp = x+y+z;
		return tmp;
	}

	static int parallel(Vector3f line_one_p1, Vector3f line_one_p2, Vector3f line_two_p1, Vector3f line_two_p2)
	{
		// return variable to describe relationship of lines.
		int return_value = 0;
		
		float x1 = line_one_p1.x;
		float y1 = line_one_p1.y;
		float z1 = line_one_p1.z;
		
		float x2 = line_one_p2.x;
		float y2 = line_one_p2.y;
		float z2 = line_one_p2.z;

		bool l_one_xy = false;
		bool l_one_zy = false;

		float mxy1 = 0; // slope of line 2 in (x,y)
		float cxy1 = 0; // y-intersect of line 2 in (x,y)
		float mzy1 = 0; // slope of line 2 in (z,y)
		float czy1 = 0; // y-intersect of line 2 in (z,y)

		//line1 in (x,y) plane = y = mx + c
		if(x1 != x2) 
		{
			mxy1 =(y1 - y2) / (x1 - x2);
			cxy1 = -1 * ((mxy1 * x2) - y2);
		}
		else
		{
			l_one_xy = true; //equation for line1 in (x,y) is x = x1;  // line is parrallel to y axis and has infinite m
		}
		//line1 in (z,y) plane = y = mx + c
		if(z1 != z2)
		{
			mzy1 =(y1 - y2) / (z1 - z2);
			czy1 = -1 * ((mzy1 * z2) - y2);
		}
		else
		{
			l_one_zy = true; //equation for line1 in (z,y) is z = z1;  // line is parrallel to y axis and has infinite m
		}
		
		float x3 = line_two_p1.x;
		float y3 = line_two_p1.y;
		float z3 = line_two_p1.z;
		
		float x4 = line_two_p2.x;
		float y4 = line_two_p2.y;
		float z4 = line_two_p2.z;

		bool l_two_xy = false;
		bool l_two_zy = false;

		float mxy2 = 0; // slope of line 2 in (x,y)
		float cxy2 = 0; // y-intersect of line 2 in (x,y)
		float mzy2 = 0; // slope of line 2 in (z,y)
		float czy2 = 0; // y-intersect of line 2 in (z,y)
		
		//line2 in (x,y) plane = y = mx + c
		if(x3 != x4)  
		{
			mxy2 =(y3 - y4) / (x3 - x4);
			cxy2 = -1 * ((mxy2 * x4) - y4);
		}
		else
		{
			l_two_xy = true; //equation for line2 in (x,y) is x = x3;  // line is parrallel to y axis and has infinite m
		}
		//line2 in (z,y) plane = y = mx + c
		if(z3 != z4)  
		{
			mzy2 =(y3 - y4) / (z3 - z4);
			czy2 = -1 * ((mzy2 * z4) - y4);
		}
		else
		{
			l_two_zy = true; //equation for line2 in (x,y) is x = x3;  // line is parrallel to y axis and has infinite m
		}
		if(l_one_xy == true && l_one_zy == true && l_two_xy && l_two_zy == true)	// check if both lines are completely vertical
		{
			return_value = 1;			//lines are all vertical
			if(x1 == x3 && z1 == z3)	// check for concurreny
			{
				return_value = 2;
			}
		}
		else if(mxy1 == mxy2 && mzy1 == mzy2)	// check if parallel when not vertical
		{
			return_value = 1;					//lines are parellel
			if(cxy1 == cxy2 && czy1 == czy2)	// check for concurrency
			{
				return_value = 2;
			}
		}
		return return_value;
	}

	static Vector3f checkIntersectionPoint(Vector3f line_one_p1, Vector3f line_one_p2, Vector3f line_two_p1, Vector3f line_two_p2)
	{
		// return variable to describe relationship of lines.
		Vector3f point;
		
		float x1 = line_one_p1.x;
		float y1 = line_one_p1.y;
		float z1 = line_one_p1.z;
		
		float x2 = line_one_p2.x;
		float y2 = line_one_p2.y;
		float z2 = line_one_p2.z;

		bool l_one_xy = false;
		bool l_one_zy = false;

		float mxy1 = 0; // slope of line 2 in (x,y)
		float cxy1 = 0; // y-intersect of line 2 in (x,y)
		float mzy1 = 0; // slope of line 2 in (z,y)
		float czy1 = 0; // y-intersect of line 2 in (z,y)

		//line1 in (x,y) plane = y = mx + c
		if(x1 != x2) 
		{
			mxy1 =(y1 - y2) / (x1 - x2);
			cxy1 = -1 * ((mxy1 * x2) - y2);
		}
		else
		{
			l_one_xy = true; //equation for line1 in (x,y) is x = x1;  // line is parrallel to y axis and has infinite m
		}
		//line1 in (z,y) plane = y = mx + c
		if(z1 != z2)
		{
			mzy1 =(y1 - y2) / (z1 - z2);
			czy1 = -1 * ((mzy1 * z2) - y2);
		}
		else
		{
			l_one_zy = true; //equation for line1 in (z,y) is z = z1;  // line is parrallel to y axis and has infinite m
		}
		
		float x3 = line_two_p1.x;
		float y3 = line_two_p1.y;
		float z3 = line_two_p1.z;
		
		float x4 = line_two_p2.x;
		float y4 = line_two_p2.y;
		float z4 = line_two_p2.z;

		bool l_two_xy = false;
		bool l_two_zy = false;

		float mxy2 = 0; // slope of line 2 in (x,y)
		float cxy2 = 0; // y-intersect of line 2 in (x,y)
		float mzy2 = 0; // slope of line 2 in (z,y)
		float czy2 = 0; // y-intersect of line 2 in (z,y)
		
		//line2 in (x,y) plane = y = mx + c
		if(x3 != x4)  
		{
			mxy2 =(y3 - y4) / (x3 - x4);
			cxy2 = -1 * ((mxy2 * x4) - y4);
		}
		else
		{
			l_two_xy = true; //equation for line2 in (x,y) is x = x3;  // line is parrallel to y axis and has infinite m
		}
		//line2 in (z,y) plane = y = mx + c
		if(z3 != z4)  
		{
			mzy2 =(y3 - y4) / (z3 - z4);
			czy2 = -1 * ((mzy2 * z4) - y4);
		}
		else
		{
			l_two_zy = true; //equation for line2 in (xzy) is z = z3  // line is parrallel to y axis and has infinite m
		}
		
		float x_at_contact = 0;
		float y_at_contact = 0;
		float z_at_contact = 0;
		if(x1 == x2)
		{
			x_at_contact = x1;
			y_at_contact = mxy1 * x_at_contact + cxy1;

			// y = mz + c
			// y - c = mz
			// (y - c) / m = z
			if(l_one_zy && l_two_zy)
			{
				z_at_contact = z1;
			}
			else if(l_one_zy)
			{
				
				z_at_contact = (y_at_contact - czy2) / mzy2;
			}
			else
			{
				z_at_contact = (y_at_contact - czy1) / mzy1;
			}		
		}
		else
		{
			x_at_contact = (cxy1 - cxy2) / (mxy1 - mxy2);  // if the lines are parallel then this will cause an error
			y_at_contact = (mxy2 * x_at_contact) + cxy2;
			// y = mz + c
			// y - c = mz
			// (y - c) / m = z
			if(l_one_zy && l_two_zy)
			{
				z_at_contact = z1;
			}
			else if(l_one_zy)
			{
				
				z_at_contact = (y_at_contact - czy2) / mzy2;
			}
			else
			{
				z_at_contact = (y_at_contact - czy1) / mzy1;
			}
		}
		point.x = x_at_contact;
		point.y = y_at_contact;
		point.z = z_at_contact;
		return point;
	}

	float x;
	float y;
	float z;
};
#endif